package com.jc.order.controller;


import cn.hutool.core.util.StrUtil;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.jc.constant.OperationTypeEnum;
import com.jc.order.service.impl.EciQuotaApplyValidator;
import com.jc.order.constant.DataStatusEnum;
import com.jc.order.constant.ErrorCode;
import com.jc.order.domain.EciCreditHistory;
import com.jc.order.dto.EciCustomerQuotaApplyDTO;
import com.jc.order.dto.EciCustomerQuotaApprovedDTO;
import com.jc.order.dto.SystemTenantDTO;
import com.jc.order.service.ApiBaseService;
import com.jc.order.service.EciCreditHistoryService;
import com.jc.order.service.EciCustomerQuotaApplyService;
import com.jc.order.service.EciCustomerQuotaApprovedService;
import com.jc.order.util.DTOCompareUtil;
import com.jc.util.Result;
import com.jc.vo.OrderRequest;
import com.jc.vo.QuotaApplyResponse;
import com.jc.vo.QuotaApplyVO;
import com.jc.vo.QuotaApprovedVO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.*;
import java.util.stream.Collectors;

@RestController
@RequestMapping("quotaApply/v1")
@Slf4j
@RequiredArgsConstructor
public class EciQuotaApplyController {

    @Autowired
    private final EciCreditHistoryService eciCreditHistoryService;

    private final ApiBaseService apiBaseService;
    private final EciCustomerQuotaApplyService customerQuotaApplyService;
    private final EciCustomerQuotaApprovedService eciCustomerQuotaApprovedService;
    private final ObjectMapper objectMapper = new ObjectMapper();

    @RequestMapping("apply")
    public Result<QuotaApplyVO> apply(@RequestBody OrderRequest request) {
        Result<QuotaApplyVO> result = new Result<>();
        try {
            // 1. 基础信息验证
            SystemTenantDTO tenant = apiBaseService.validateBaseInfo(request, result);
            if (!result.getSuccess()) {
                result.setCode(ErrorCode.BASE_INFO_ERROR);
                return result;
            }

            // 2. 数据转换
            QuotaApplyVO applyVO = parseDTO(request.getData(), result);
            if (!result.getSuccess()) {
                return result;
            }

            // 3. DTO转换与校验
            EciCustomerQuotaApplyDTO dto = convertToDTO(applyVO, tenant);
            List<String> errors = EciQuotaApplyValidator.validate(dto);
            if (!errors.isEmpty()) {
                return buildValidationErrorResult(applyVO, errors);
            }

            // 4. 业务流程路由
            OperationTypeEnum operationType = OperationTypeEnum.getByCode(dto.getOperationType());
            switch (operationType) {
                case NEW:
                    processNewInsuranceFlow(dto, result);
                    break;
                case MODIFY:
                    processModifyInsuranceFlow(dto, result);
                    break;
                case CHANGE:
                    processChangeInsuranceFlow(dto, result);
                    break;
                default:
                    result.error(ErrorCode.INVALID_OPERATION_TYPE, "操作类型(operationType)只能填写[NEW,MODIFY,CHANGE]");
            }

            // 5. 响应构建
            return buildFinalResult(result, applyVO, dto);
        } catch (Exception e) {
            log.error("限额申请系统异常: request={}", request, e);
            return new Result().error("系统处理异常，请稍后重试");
        }
    }

    @RequestMapping("queryQuotaApproved")
    public Result<List<QuotaApplyVO>> queryQuotaApproved(@RequestBody OrderRequest request) {
        Result<List<QuotaApplyVO>> result = new Result<>();
        try {
            // 1. 基础信息验证
            SystemTenantDTO tenant = apiBaseService.validateBaseInfo(request, result);
            if (!result.getSuccess()) {
                return result;
            }

            // 2. 参数解析与校验
            List<String> snNoList = parseSnNos(request.getData());
            if (CollectionUtils.isEmpty(snNoList)) {
                return new Result().error(ErrorCode.QUERY_PARAM_MISSING, "缺少关键查询参数 corpSerialNos");
            }
            if (snNoList.size() > 500) {
                return new Result().error(ErrorCode.QUERY_TOO_LARGE, "查询数据量过大，请拆分多次请求");
            }

            // 3. 数据查询
            List<EciCustomerQuotaApplyDTO> dtoList = customerQuotaApplyService.getBySerialNoList(snNoList, tenant.getId());
            if (CollectionUtils.isEmpty(dtoList)) {
                return new Result().ok(Collections.emptyList());
            }

            // 4. 构建响应
            return new Result().ok(buildQuotaResponse(dtoList, tenant.getId()));
        } catch (Exception e) {
            log.error("限额查询系统异常: request={}", request, e);
            return new Result().error("系统处理异常，请稍后重试");
        }
    }

    // --- 辅助方法 ---
    private EciCustomerQuotaApplyDTO convertToDTO(QuotaApplyVO vo, SystemTenantDTO tenant) {
        EciCustomerQuotaApplyDTO dto = new EciCustomerQuotaApplyDTO();
        BeanUtils.copyProperties(vo, dto);
        dto.setTenantId(tenant.getId());
        dto.setDataStatus(DataStatusEnum.DATA_STATUS_1.getCode());
        return dto;
    }

    private Result<QuotaApplyVO> buildValidationErrorResult(QuotaApplyVO vo, List<String> errors) {
        QuotaApplyResponse response = new QuotaApplyResponse();
        response.setErrors(errors);
        vo.setResponse(response);
        Result<QuotaApplyVO> result = new Result().error(ErrorCode.VALIDATION_FAILED, "数据校验未通过");
        result.setContent(vo);
        return result;
    }

    private Result<QuotaApplyVO> buildFinalResult(Result<QuotaApplyVO> result,
                                                  QuotaApplyVO applyVO,
                                                  EciCustomerQuotaApplyDTO dto) {
        if (result.getSuccess()) {
            QuotaApplyResponse response = new QuotaApplyResponse();
            response.setCorpSerialNo(dto.getCorpSerialNo());
            response.setDataStatus(dto.getDataStatus());
            response.setBusinessType(dto.getBusinessType());
            applyVO.setResponse(response);
            return new Result().ok(applyVO);
        } else {
            QuotaApplyResponse response = new QuotaApplyResponse();
            response.setErrors(Collections.singletonList(result.getMessage()));
            applyVO.setResponse(response);
            return new Result().error(result.getMessage(), applyVO);
        }
    }

    private List<QuotaApplyVO> buildQuotaResponse(List<EciCustomerQuotaApplyDTO> applyList, Long tenantId) {
        List<String> serialNos = applyList.stream()
                .map(EciCustomerQuotaApplyDTO::getCorpSerialNo)
                .collect(Collectors.toList());

        Map<String, EciCustomerQuotaApprovedDTO> approvedMap = eciCustomerQuotaApprovedService
                .selectByCorpSerialNos(serialNos, tenantId)
                .stream()
                .collect(Collectors.toMap(
                        EciCustomerQuotaApprovedDTO::getCorpSerialNo,
                        dto -> dto
                ));

        return applyList.stream().map(applyDTO -> {
            QuotaApplyVO vo = new QuotaApplyVO();
            BeanUtils.copyProperties(applyDTO, vo);

            QuotaApplyResponse response = new QuotaApplyResponse();
            response.setCorpSerialNo(applyDTO.getCorpSerialNo());
            response.setDataStatus(applyDTO.getDataStatus());
            response.setBusinessType(applyDTO.getBusinessType());
            vo.setResponse(response);

            Optional.ofNullable(approvedMap.get(applyDTO.getCorpSerialNo()))
                    .ifPresent(approved -> {
                        QuotaApprovedVO approvedVO = new QuotaApprovedVO();
                        BeanUtils.copyProperties(approved, approvedVO);
                        vo.setQuotaApprovedVO(approvedVO);
                    });

            return vo;
        }).collect(Collectors.toList());
    }

    private List<String> parseSnNos(String data) {
        if (StrUtil.isEmpty(data)) {
            return Collections.emptyList();
        }

        try {
            Map<String, String> map = objectMapper.readValue(data, new TypeReference<Map<String, String>>() {
            });
            String snNos = map.get("corpSerialNos");

            return Optional.ofNullable(snNos)
                    .map(str -> Arrays.stream(str.split(","))
                            .filter(StrUtil::isNotBlank)
                            .collect(Collectors.toList()))
                    .orElse(Collections.emptyList());
        } catch (JsonProcessingException e) {
            log.error("请求数据解析失败: {}", data, e);
            return null;
        }
    }

    private QuotaApplyVO parseDTO(String jsonData, Result<QuotaApplyVO> result) {
        try {
//            return objectMapper.readValue(jsonData, new TypeReference<>() {});
            QuotaApplyVO applyVO = objectMapper.readValue(jsonData, new TypeReference<QuotaApplyVO>() {
            });
            return applyVO;
        } catch (JsonProcessingException e) {
            log.error("请求数据解析失败: {}", jsonData, e);
            result.error(ErrorCode.DATA_PARSE_ERROR, "数据格式错误");
            return null;
        }
    }

    private void processNewInsuranceFlow(EciCustomerQuotaApplyDTO dto, Result<QuotaApplyVO> result) {
        List<EciCustomerQuotaApplyDTO> existing = customerQuotaApplyService.getByDTO(dto);
        if (existing != null && existing.size() > 0) {
            existing.stream()
                    .filter(e -> e.getRiskCompName().equalsIgnoreCase(dto.getRiskCompName()))
                    .findFirst()
                    .ifPresent(e -> result.error(ErrorCode.DUPLICATE_APPLICATION, "买方名称[" + dto.getRiskCompName() + "] 已存在限额申请"));

            existing.stream()
                    .filter(e -> e.getRiskMark().equalsIgnoreCase(dto.getRiskMark()))
                    .findFirst()
                    .ifPresent(e -> result.error(ErrorCode.DUPLICATE_APPLICATION, "买方注册号[" + dto.getRiskMark() + "] 已存在限额申请"));

            return;
        }

        if (customerQuotaApplyService.createQuotaApply(dto) == null) {
            result.error("限额申请创建失败");
        }
    }

    private void processModifyInsuranceFlow(EciCustomerQuotaApplyDTO dto, Result<QuotaApplyVO> result) {
        EciCustomerQuotaApplyDTO existing = customerQuotaApplyService.getBySerialNo(
                dto.getCorpSerialNo(), dto.getTenantId());

        if (existing == null) {
            result.error(ErrorCode.RECORD_NOT_FOUND, "流水号[" + dto.getCorpSerialNo() + "] 不存在");
            return;
        }

        if (!DataStatusEnum.DATA_STATUS_REFUSE.getCode().equalsIgnoreCase(existing.getDataStatus())) {
            result.error(ErrorCode.INVALID_STATUS,"流水号[" + dto.getCorpSerialNo() + "] 当前状态不能修改");
            return;
        }

        List<DTOCompareUtil.FieldChange> changes = DTOCompareUtil.compareObjectChanges(existing, dto);
        if (changes.isEmpty()) {
            result.error("未检测到修改内容");
            return;
        }

        dto.setId(existing.getId());
        dto.setCreateTime(existing.getCreateTime());
        dto.setCreateUser(existing.getCreateUser());
        if (!customerQuotaApplyService.updateQuotaApply(dto)) {
            result.error("限额申请更新失败");
        } else {
//            changes.forEach(change -> log.debug("限额修改字段变更: {}", change));
            this.saveHistory(changes, dto);
        }
    }

    private void processChangeInsuranceFlow(EciCustomerQuotaApplyDTO dto, Result<QuotaApplyVO> result) {
        EciCustomerQuotaApplyDTO existing = customerQuotaApplyService.getBySerialNo(
                dto.getOriginalCorpSerialNo(), dto.getTenantId());

        if (existing == null) {
            result.error(ErrorCode.RECORD_NOT_FOUND, "原始流水号[" + dto.getOriginalCorpSerialNo() + "] 不存在");
            return;
        }

        if (!DataStatusEnum.DATA_STATUS_PASS.getCode().equalsIgnoreCase(existing.getDataStatus())) {
            result.error(ErrorCode.INVALID_STATUS, "原始流水号[" + dto.getOriginalCorpSerialNo() + "] 当前状态不能变更");
            return;
        }

        List<DTOCompareUtil.FieldChange> changes = DTOCompareUtil.compareObjectChanges(existing, dto);
        if (changes.isEmpty()) {
            result.error(ErrorCode.NO_CHANGES_DETECTED, "未检测到变更内容");
            return;
        }

        if (customerQuotaApplyService.createQuotaApply(dto) == null) {
            result.error("限额变更申请创建失败");
        } else {
            this.saveHistory(changes, dto);
        }
    }


    private void saveHistory(List<DTOCompareUtil.FieldChange> changes, EciCustomerQuotaApplyDTO dto) {
        if (!changes.isEmpty()) {
            log.info("限额变更: corpSerialNo={}, 变更字段数={}", dto.getCorpSerialNo(), changes.size());
            StringBuffer buffer = new StringBuffer();
            changes.forEach(change -> buffer.append(change.toString()).append(";"));
            EciCreditHistory history = new EciCreditHistory();
            history.setTitle(OperationTypeEnum.getByCode(dto.getOperationType()).getValue());
            history.setTenantId(dto.getTenantId());
            history.setCorpSerialNo(dto.getCorpSerialNo());
            history.setCreateTime(new Date());
            history.setContent(buffer.toString());
            history.setDataSource(1);
            eciCreditHistoryService.addHistory(history);
        }
    }


}